//
//	HOME AUTOMATION GATEWAY PROJECT
//
//  (c) 2008 mocom software GmbH & Co KG
//	for European Microsoft Innovation Center
//
//  $Author: volker $
//  $Date: 2009-05-04 18:13:33 +0200 (Mo, 04. Mai 2009) $
//  $Revision: 335 $
//
//  Microsoft dotNetMF Project
//  Copyright ©2001,2002,2003,2004 Microsoft Corporation
//  One Microsoft Way, Redmond, Washington 98052-6399 U.S.A.
//  All rights reserved.
//  MICROSOFT CONFIDENTIAL
//
//-----------------------------------------------------------------------------

#include <tinyhal.h>

#define BOARD_OSCOUNT           (AT91_PMC::CKGR_OSCOUNT & (64 << 8))
#define BOARD_CKGR_PLLA         ( (0x1 << 29) | AT91_PMC::CKGR_OUT_2)
#define BOARD_PLLACOUNT         (63 << 8)
#define BOARD_MULA              (AT91_PMC::CKGR_MUL & (96 << 16))
#define BOARD_DIVA              (AT91_PMC::CKGR_DIV & 9)
#define BOARD_PRESCALER         AT91_PMC::PMC_MDIV_2

#define BOARD_USBDIV            AT91_PMC::CKGR_USBDIV_2
#define BOARD_CKGR_PLLB         AT91_PMC::CKGR_OUT_0
#define BOARD_PLLBCOUNT         BOARD_PLLACOUNT
#define BOARD_MULB              (124 << 16)
#define BOARD_DIVB              12

#define READ(peripheral, register)          (peripheral->register)
#define WRITE(peripheral, register, value)  (peripheral->register = value)

/*
* Setup PLL & SDRAM
*/
void AT91_HAG_ClockInit(void)
{
    // Power Management Controller
    struct AT91_PMC *pAT91_PMC = (struct AT91_PMC*) AT91_PMC::c_Base;

    // Initialize main oscillator
    pAT91_PMC->PMC_CKGR_MOR = BOARD_OSCOUNT | AT91_PMC::CKGR_MOSCEN;
    while (!(pAT91_PMC->PMC_SR & AT91_PMC::PMC_MOSCS));

    // Initialize PLLA at 200MHz (198.656)
    pAT91_PMC->PMC_CKGR_PLLAR = BOARD_CKGR_PLLA
                                | BOARD_PLLACOUNT
                                | BOARD_MULA
                                | BOARD_DIVA;
    while (!(pAT91_PMC->PMC_SR & AT91_PMC::PMC_LOCKA));

    // Initialize PLLB for USB usage
    pAT91_PMC->PMC_CKGR_PLLR = BOARD_USBDIV
                                | BOARD_CKGR_PLLB
                                | BOARD_PLLBCOUNT
                                | BOARD_MULB
                                | BOARD_DIVB;
    while (!(pAT91_PMC->PMC_SR & AT91_PMC::PMC_LOCK));

    // Wait for the master clock if it was already initialized
    while (!(pAT91_PMC->PMC_SR & AT91_PMC::PMC_MCKRDY));

    // Switch to fast clock
    // Switch to main oscillator + prescaler
    pAT91_PMC->PMC_MCKR = BOARD_PRESCALER;
    while (!(pAT91_PMC->PMC_SR & AT91_PMC::PMC_MCKRDY));

    // Switch to PLL + prescaler
    pAT91_PMC->PMC_MCKR |= AT91_PMC::PMC_CSS_PLLA_CLK;
    while (!(pAT91_PMC->PMC_SR & AT91_PMC::PMC_MCKRDY));
}


#define GPIO_PIN_TO_PORT(x) (x / AT91_GPIO_Driver::c_PinsPerPort)
#define GPIO_PIN_TO_BIT(x)  (x % AT91_GPIO_Driver::c_PinsPerPort)

/*
* Localize the SDRAM GPIO pin disable code because we are not fully initialized
* In particular, the SmartPtr (GLOBAL_LOCK) code is mapped to the 0 address space
* which isn't valid until MMU is initialized.
*/
void AT91_HAG_Sdram_DisablePin(UINT32 gpioPin)
{
    struct AT91_PIO * pPioX = (struct AT91_PIO *)(AT91C_BASE_PIOA + GPIO_PIN_TO_PORT(gpioPin) * 0x200);
    UINT32 bit = GPIO_PIN_TO_BIT(gpioPin);

    pPioX->PIO_PPUDR = bit;
    pPioX->PIO_PDR   = bit;
    pPioX->PIO_ASR   = bit;
    pPioX->PIO_IDR   = bit;
}


void AT91_HAG_SdramInit(void)
{
  	// JACK enabled SDRAM but GPIO init kills the I/O lines.
	
    // Affect PIO lines to SDRAM controller
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC16 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC17 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC18 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC19 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC20 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC21 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC22 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC23 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC24 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC25 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC26 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC27 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC28 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC29 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC30 );
    AT91_HAG_Sdram_DisablePin( AT91_GPIO_Driver::PC31 );

/*	
    volatile UINT32 *pSdram = (volatile UINT32*) SDRAM_MEMORY_Base;
    int i;

	// AT91 Bus Matrix controller
    struct AT91_MATRIX *pMatrix = (struct AT91_MATRIX *)AT91C_BASE_MATRIX;

    // Enable EBI chip select for the SDRAM
    WRITE(pMatrix, MATRIX_EBICSA, AT91C_MATRIX_CS1A_SDRAMC);

    // Sdramc Controller
    struct AT91_SDRAMC *pAT91_SDRAMC = (struct AT91_SDRAMC*) AT91C_BASE_SDRAMC;

    // CFG Control Register
#if defined (SDRAM64)
    pAT91_SDRAMC->SDRAMC_CR = (   AT91C_SDRAMC_NC_9
                                | AT91C_SDRAMC_NR_13
                                | AT91C_SDRAMC_CAS_2
                                | AT91C_SDRAMC_NB_4_BANKS
                                | AT91C_SDRAMC_DBW_32_BITS
                                | AT91C_SDRAMC_TWR_2
                                | AT91C_SDRAMC_TRC_7
                                | AT91C_SDRAMC_TRP_2
                                | AT91C_SDRAMC_TRCD_2
                                | AT91C_SDRAMC_TRAS_5
                                | AT91C_SDRAMC_TXSR_8);
#elif defined (SDRAM32)
   pAT91_SDRAMC->SDRAMC_CR = (   AT91C_SDRAMC_NC_9
                                | AT91C_SDRAMC_NR_12
                                | AT91C_SDRAMC_CAS_3
                                | AT91C_SDRAMC_NB_4_BANKS
                                | AT91C_SDRAMC_DBW_32_BITS
                                | AT91C_SDRAMC_TWR_2
                                | AT91C_SDRAMC_TRC_7
                                | AT91C_SDRAMC_TRP_2
                                | AT91C_SDRAMC_TRCD_2
                                | AT91C_SDRAMC_TRAS_5
                                | AT91C_SDRAMC_TXSR_8);
#endif
        for (i = 0; i < 100000; i++);

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NOP_CMD);          // Perform NOP
        pSdram[0] = 0x00000000;

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_PRCGALL_CMD);      // Set PRCHG AL
        pSdram[0] = 0x00000000;                                             // Perform PRCHG

        for (i = 0; i < 100000; i++);

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 1st CBR
        pSdram[1] = 0x00000001;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 2 CBR
        pSdram[2] = 0x00000002;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 3 CBR
        pSdram[3] = 0x00000003;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 4 CBR
        pSdram[4] = 0x00000004;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 5 CBR
        pSdram[5] = 0x00000005;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 6 CBR
        pSdram[6] = 0x00000006;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 7 CBR
        pSdram[7] = 0x00000007;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_RFSH_CMD);        // Set 8 CBR
        pSdram[8] = 0x00000008;                                                 // Perform CBR

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_LMR_CMD);         // Set LMR operation
        pSdram[9] = 0xcafedede;                                                 // Perform LMR burst=1, lat=2

        WRITE(pAT91_SDRAMC, SDRAMC_TR, (SYSTEM_PERIPHERAL_CLOCK_HZ * 7) / 1000000); // Set Refresh Timer

        WRITE(pAT91_SDRAMC, SDRAMC_MR, AT91C_SDRAMC_MODE_NORMAL_CMD);      // Set Normal mode
        pSdram[0] = 0x00000000;
        pSdram[0] = 0x00000000;
		
		*/
}

/* ******************************************************************** */
/* SMC Chip Select 2 Timings for ETH for MASTER_CLOCK = 100000000.		*/
/* Please refer to SMC section in AT91SAM9 datasheet to learn how 		*/
/* to generate these values. 											*/
/* ******************************************************************** */
#define AT91C_SM_NWE_SETUP_2		(0 << 0)
#define AT91C_SM_NCS_WR_SETUP_2		(0 << 8)
#define AT91C_SM_NRD_SETUP_2		(0 << 16)
#define AT91C_SM_NCS_RD_SETUP_2		(0 << 24)

#define AT91C_SM_NWE_PULSE_2 		(8 << 0)
#define AT91C_SM_NCS_WR_PULSE_2		(8 << 8)
#define AT91C_SM_NRD_PULSE_2		(8 << 16)
#define AT91C_SM_NCS_RD_PULSE_2		(8 << 24)

#define AT91C_SM_NWE_CYCLE_2 		(10 << 0)
#define AT91C_SM_NRD_CYCLE_2		(10 << 16)

#define AT91C_SM_TDF_2	        	(2 << 16)

/* ******************************************************************** */
/* SMC Chip Select 3 Timings for NandFlash for MASTER_CLOCK = 100000000.*/
/* Please refer to SMC section in AT91SAM9 datasheet to learn how 	*/
/* to generate these values. 						*/
/* ******************************************************************** */
#define AT91C_SM_NWE_SETUP_3		(2 << 0)
#define AT91C_SM_NCS_WR_SETUP_3		(1 << 8)
#define AT91C_SM_NRD_SETUP_3		(2 << 16)
#define AT91C_SM_NCS_RD_SETUP_3		(1 << 24)

#define AT91C_SM_NWE_PULSE_3 		(3 << 0)
#define AT91C_SM_NCS_WR_PULSE_3		(5 << 8)
#define AT91C_SM_NRD_PULSE_3		(3 << 16)
#define AT91C_SM_NCS_RD_PULSE_3		(5 << 24)

#define AT91C_SM_NWE_CYCLE_3 		(6 << 0)
#define AT91C_SM_NRD_CYCLE_3		(8 << 16)

#define AT91C_SM_TDF_3	        	(2 << 16)

/* ******************************************************************** */
/* SMC Chip Select 4 Timings for UART for MASTER_CLOCK = 100000000.		*/
/* Please refer to SMC section in AT91SAM9 datasheet to learn how 		*/
/* to generate these values. 											*/
/* ******************************************************************** */
#define AT91C_SM_NWE_SETUP_4		(2 << 0)
#define AT91C_SM_NCS_WR_SETUP_4		(0 << 8)
#define AT91C_SM_NRD_SETUP_4		(1 << 16)
#define AT91C_SM_NCS_RD_SETUP_4		(2 << 24)

#define AT91C_SM_NWE_PULSE_4 		(10 << 0)
#define AT91C_SM_NCS_WR_PULSE_4		(14 << 8)
#define AT91C_SM_NRD_PULSE_4		(12 << 16)
#define AT91C_SM_NCS_RD_PULSE_4		(16 << 24)

#define AT91C_SM_NWE_CYCLE_4 		(22 << 0)
#define AT91C_SM_NRD_CYCLE_4		(20 << 16)

#define AT91C_SM_TDF_4	        	(4 << 16)

/* ******************************************************************** */
/* SMC CONTROL VALUES													*/
/* ******************************************************************** */
#define AT91C_SMC_READMODE        				(0x1 <<  0) // (SMC) Read Mode
#define AT91C_SMC_WRITEMODE       				(0x1 <<  1) // (SMC) Write Mode
#define AT91C_SMC_NWAITM          				(0x3 <<  5) // (SMC) NWAIT Mode
#define AT91C_SMC_NWAITM_NWAIT_DISABLE        	(0x0 <<  5) // (SMC) External NWAIT disabled.
#define AT91C_SMC_NWAITM_NWAIT_ENABLE_FROZEN  	(0x2 <<  5) // (SMC) External NWAIT enabled in frozen mode.
#define AT91C_SMC_NWAITM_NWAIT_ENABLE_READY   	(0x3 <<  5) // (SMC) External NWAIT enabled in ready mode.
#define AT91C_SMC_BAT             				(0x1 <<  8) // (SMC) Byte Access Type
#define AT91C_SMC_BAT_BYTE_SELECT          		(0x0 <<  8) // (SMC) Write controled by ncs, nbs0, nbs1, nbs2, nbs3. Read controled by ncs, nrd, nbs0, nbs1, nbs2, nbs3.
#define AT91C_SMC_BAT_BYTE_WRITE           		(0x1 <<  8) // (SMC) Write controled by ncs, nwe0, nwe1, nwe2, nwe3. Read controled by ncs and nrd.
#define AT91C_SMC_DBW             				(0x3 << 12) // (SMC) Data Bus Width
#define AT91C_SMC_DBW_WIDTH_EIGTH_BITS     		(0x0 << 12) // (SMC) 8 bits.
#define AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS   		(0x1 << 12) // (SMC) 16 bits.
#define AT91C_SMC_DBW_WIDTH_THIRTY_TWO_BITS 	(0x2 << 12) // (SMC) 32 bits.
#define AT91C_SMC_TDF             				(0xF << 16) // (SMC) Data Float Time.
#define AT91C_SMC_TDFEN           				(0x1 << 20) // (SMC) TDF Enabled.
#define AT91C_SMC_PMEN            				(0x1 << 24) // (SMC) Page Mode Enabled.
#define AT91C_SMC_PS              				(0x3 << 28) // (SMC) Page Size
#define AT91C_SMC_PS_SIZE_FOUR_BYTES      		(0x0 << 28) // (SMC) 4 bytes.
#define AT91C_SMC_PS_SIZE_EIGHT_BYTES     		(0x1 << 28) // (SMC) 8 bytes.
#define AT91C_SMC_PS_SIZE_SIXTEEN_BYTES   		(0x2 << 28) // (SMC) 16 bytes.
#define AT91C_SMC_PS_SIZE_THIRTY_TWO_BYTES 		(0x3 << 28) // (SMC) 32 bytes.

#define PIO_NB_IO			32 /* Number of IO handled by one PIO controller */
#define	AT91C_PIN_PA(io)	(0 * PIO_NB_IO + io)
#define	AT91C_PIN_PB(io)	(1 * PIO_NB_IO + io)
#define	AT91C_PIN_PC(io)	(2 * PIO_NB_IO + io)

/* Convert Pin Number into PIO controller index */
static inline struct AT91_PIO * pin_to_controller(unsigned pin)
{
	if (pin < 32)
		return (struct AT91_PIO *) AT91C_BASE_PIOA;
	if (pin < 64)
		return (struct AT91_PIO *) AT91C_BASE_PIOB;
	if (pin < 96)
		return (struct AT91_PIO *) AT91C_BASE_PIOC;
	return NULL;
}

/* Convert Pin Number into I/O line index */
static inline unsigned pin_to_mask(unsigned pin)
{
	return 1 << ((pin) % PIO_NB_IO);
}

void HAG_Init(void)
{
	struct AT91_SMC *pAT91_SMC = (struct AT91_SMC *) AT91C_BASE_SMC;
    struct AT91_MATRIX *pMatrix = (struct AT91_MATRIX *)AT91_MATRIX::c_Base;
	struct AT91_PIO *pioX;
	UINT32 mask;

    /* Configures SMC CS3 for NandFlash access at 48MHz	*/
    pAT91_SMC->SMC_SETUP3 = (AT91C_SM_NWE_SETUP_3 | AT91C_SM_NCS_WR_SETUP_3 | AT91C_SM_NRD_SETUP_3 | AT91C_SM_NCS_RD_SETUP_3);
    pAT91_SMC->SMC_PULSE3 = (AT91C_SM_NWE_PULSE_3 | AT91C_SM_NCS_WR_PULSE_3 | AT91C_SM_NRD_PULSE_3 | AT91C_SM_NCS_RD_PULSE_3);
    pAT91_SMC->SMC_CYCLE3 = (AT91C_SM_NWE_CYCLE_3 | AT91C_SM_NRD_CYCLE_3);
    pAT91_SMC->SMC_CTRL3  = (AT91C_SMC_READMODE | AT91C_SMC_WRITEMODE | AT91C_SMC_NWAITM_NWAIT_DISABLE |
  		                                  AT91C_SMC_DBW_WIDTH_EIGTH_BITS | AT91C_SM_TDF_3);

	/* Configure SMC CS2, ETHERNET */
	pAT91_SMC->SMC_SETUP2 = (AT91C_SM_NWE_SETUP_2 | AT91C_SM_NCS_WR_SETUP_2 | AT91C_SM_NRD_SETUP_2 | AT91C_SM_NCS_RD_SETUP_2);
  	pAT91_SMC->SMC_PULSE2 = (AT91C_SM_NWE_PULSE_2 | AT91C_SM_NCS_WR_PULSE_2 | AT91C_SM_NRD_PULSE_2 | AT91C_SM_NCS_RD_PULSE_2);
	pAT91_SMC->SMC_CYCLE2 = (AT91C_SM_NWE_CYCLE_2 | AT91C_SM_NRD_CYCLE_2);
	pAT91_SMC->SMC_CTRL2  = (AT91C_SMC_READMODE | AT91C_SMC_WRITEMODE | AT91C_SMC_NWAITM_NWAIT_DISABLE |
							  AT91C_SMC_DBW_WIDTH_SIXTEEN_BITS | AT91C_SMC_BAT_BYTE_SELECT | AT91C_SM_TDF_2);

	/* Configure SMC CS4, UART */
 	pAT91_SMC->SMC_SETUP4 = (AT91C_SM_NWE_SETUP_4 | AT91C_SM_NCS_WR_SETUP_4 | AT91C_SM_NRD_SETUP_4 | AT91C_SM_NCS_RD_SETUP_4);
  	pAT91_SMC->SMC_PULSE4 = (AT91C_SM_NWE_PULSE_4 | AT91C_SM_NCS_WR_PULSE_4 | AT91C_SM_NRD_PULSE_4 | AT91C_SM_NCS_RD_PULSE_4);
	pAT91_SMC->SMC_CYCLE4 = (AT91C_SM_NWE_CYCLE_4 | AT91C_SM_NRD_CYCLE_4);
	pAT91_SMC->SMC_CTRL4  = (AT91C_SMC_READMODE | AT91C_SMC_WRITEMODE | AT91C_SMC_NWAITM_NWAIT_DISABLE |
							  AT91C_SMC_DBW_WIDTH_EIGTH_BITS | AT91C_SM_TDF_4);

	/* set matrix controller */
    pMatrix->MATRIX_EBICSA |= (AT91_MATRIX::MATRIX_CS3A_SM | AT91_MATRIX::MATRIX_CS4A_SMC);

	/* PDIS */
	mask = pin_to_mask(37);
	pioX = pin_to_controller(37);
	pioX->PIO_IDR 	= mask;		// no interrupts
	pioX->PIO_PPUDR = mask;		// no pull up
	pioX->PIO_SODR 	= mask; 	// set t output to one
	pioX->PIO_OER 	= mask;		// enable output
	pioX->PIO_PER 	= mask;		// enable io
}
/*
void HAG_PB22_On(bool on)
{
	struct AT91_PIO *pioX;
	UINT32 mask;
	// PB22
	mask = pin_to_mask(54);
	pioX = pin_to_controller(54);
	pioX->PIO_IDR 	= mask;		// no interrupts
	pioX->PIO_PPUDR = mask;		// no pull up
	if (on)
	{
		pioX->PIO_SODR 	= mask; 	// set t output to one
	}
	else
	{
		pioX->PIO_CODR 	= mask; 	// set t output to zero
	}
	pioX->PIO_OER 	= mask;		// enable output
	pioX->PIO_PER 	= mask;		// enable io
}
*/
